package com.skillworld.webapp.model.util;

import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.Iterator;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.skillworld.webapp.model.bag.Bag;
import com.skillworld.webapp.model.bag.BagDao;
import com.skillworld.webapp.model.bag.ItemRecordDao;
import com.skillworld.webapp.model.department.Department;
import com.skillworld.webapp.model.department.DepartmentDao;
import com.skillworld.webapp.model.department.DepartmentRanking;
import com.skillworld.webapp.model.department.DepartmentRankingDao;
import com.skillworld.webapp.model.department.rank.DeptRankDao;
import com.skillworld.webapp.model.item.Item;
import com.skillworld.webapp.model.item.ItemDao;
import com.skillworld.webapp.model.itemservice.ItemService;
import com.skillworld.webapp.model.team.Team;
import com.skillworld.webapp.model.team.TeamDao;
import com.skillworld.webapp.model.team.TeamRanking;
import com.skillworld.webapp.model.team.TeamRankingDao;
import com.skillworld.webapp.model.tutorial.Tutorial;
import com.skillworld.webapp.model.tutorial.TutorialDao;
import com.skillworld.webapp.model.tutorial.TutorialRanking;
import com.skillworld.webapp.model.tutorial.TutorialRankingDao;
import com.skillworld.webapp.model.user.User;
import com.skillworld.webapp.model.user.UserDao;
import com.skillworld.webapp.model.user.UserRanking;
import com.skillworld.webapp.model.user.UserRankingDao;

/**
 * Scheduler for handling jobs
 * here there are considered two distinct approachs:
 * 1 - 
 * 2 -
 */
@Service("ScheduleService")
@Transactional
public class ScheduleServiceImpl implements ScheduleService
{
    private final static double PERCENT_LEADERS = 0.05;
    private final static long MIN_NUMBER_OF_LEADERS = 2;
    private final static int NUMBER_OF_TOP_TUTORIALS = 5;
    private final static int NUMBER_OF_TOP_USERS = 5;
    private final static int NUMBER_OF_TOP_DEPARTMENTS = 5;
    private final static int NUMBER_OF_TOP_TEAMS = 5;
    
    @Autowired
    ItemDao itemDao;
    
    @Autowired
    ItemService itemService;
    
    @Autowired
    TeamDao teamDao;
    
    @Autowired
    TeamRankingDao teamRankingDao;
    
    @Autowired
    UserDao userDao;
    
    @Autowired
    UserRankingDao userRankingDao;
    
    @Autowired
    DepartmentDao departmentDao;
    
    @Autowired
    DepartmentRankingDao departmentRankingDao;
    
    @Autowired
    TutorialDao tutorialDao;
    
    @Autowired
    DeptRankDao deptRankDao;
    
    @Autowired
    TutorialRankingDao tutorialRankingDao;
    
    @Autowired
    ItemRecordDao itemRecordDao;
    
    @Autowired
    BagDao bagDao;
    
    
    @Scheduled(cron="0 1 * * 6 ?")//1 am on every Saturday
    public void giveCasinoItem()
    {
        Iterator<Bag> iterator = null;
        Item item = null;
        Calendar calen = null;
        Bag bag = null;
        //
        
        try
        { 
            item = this.itemDao.getCasinoItem();
            iterator = this.bagDao.iteratorFindAll();
        }
        catch(Exception e){ }
        
        calen = new GregorianCalendar();
        calen.add(Calendar.DAY_OF_YEAR, 7);
        
        while(iterator.hasNext())
        {
            bag = iterator.next();
            if(!bag.isFull())
            { bag.addItem(item, calen); }
        }
    }


    @Scheduled(cron="0 1 1 * * ?")//minute 0 on 1 am on day 1 of month
    public void chooseDepartmentLeader() {
        
        List<Department> departments = departmentDao.findAll();
        
        Long deptId = null;
        long numberUsers = 0;
        for(Department dept :departments){
            
            dept.getLeaders().clear();
            
            deptId = dept.getDepartmentId();
            numberUsers = deptRankDao.numberOfUsersInDepartment(deptId);
            List<User> users = deptRankDao.findNewDepartmentLeaders(deptId, (int) getNumberOfMaxLeaders(numberUsers));
            
            for(User user :users){
                dept.addLeader(user);
            }
        }
    }
   
    @Scheduled(cron="5 1 1 * * ?")//minute 5 on 1 am on day 1 of month
    public void doRankingTutoriais(){
        List<Tutorial> tutorials = tutorialDao.topTutorials(NUMBER_OF_TOP_TUTORIALS);
        
        int size = tutorials.size();
        Tutorial tut1 = (size >= 1)?tutorials.get(0):null;
        Tutorial tut2 = (size >= 2)?tutorials.get(1):null;
        Tutorial tut3 = (size >= 3)?tutorials.get(2):null;
        Tutorial tut4 = (size >= 4)?tutorials.get(3):null;
        Tutorial tut5 = (size == 5)?tutorials.get(4):null;
        
        TutorialRanking tutRanking = new TutorialRanking(Calendar.getInstance().getTime(), tut1,
                tut2, tut3, tut4, tut5);
        
        tutorialRankingDao.save(tutRanking);
        
    }
    
    @Scheduled(cron="10 1 1 * * ?")//minute 10 on 1 am on day 1 of month
    public void doRankingUsers(){
        List<User> users = userDao.topUsers(NUMBER_OF_TOP_USERS);
        
        int size = users.size();
        User user1 = (size >= 1)?users.get(0):null;
        User user2 = (size >= 2)?users.get(1):null;
        User user3 = (size >= 3)?users.get(2):null;
        User user4 = (size >= 4)?users.get(3):null;
        User user5 = (size == 5)?users.get(4):null;
        
        UserRanking userRanking = new UserRanking(Calendar.getInstance().getTime(), user1,
                user2, user3, user4, user5);
        
        userRankingDao.save(userRanking);
    }
    
    @Scheduled(cron="20 1 1 * * ?")//minute 20 on 1 am on day 1 of month
    public void doRankingDepartments(){
        List<Department> departments = departmentRankingDao.topDepartments(NUMBER_OF_TOP_DEPARTMENTS);
        
        int size = departments.size();
        Department dept1 = (size >= 1)?departments.get(0):null;
        Department dept2 = (size >= 2)?departments.get(1):null;
        Department dept3 = (size >= 3)?departments.get(2):null;
        Department dept4 = (size >= 4)?departments.get(3):null;
        Department dept5 = (size == 5)?departments.get(4):null;
        
        DepartmentRanking deptRanking = new DepartmentRanking(Calendar.getInstance().getTime(), dept1,
                dept2, dept3, dept4, dept5);
        
        departmentRankingDao.save(deptRanking);
    }
    
    @Scheduled(cron="15 1 1 * * ?")//minute 15 on 1 am on day 1 of month
    public void doRankingTeams(){
        List<Team> teams = teamDao.topTeams(NUMBER_OF_TOP_TEAMS);
        
        int size = teams.size();
        Team team1 = (size >= 1)?teams.get(0):null;
        Team team2 = (size >= 2)?teams.get(1):null;
        Team team3 = (size >= 3)?teams.get(2):null;
        Team team4 = (size >= 4)?teams.get(3):null;
        Team team5 = (size == 5)?teams.get(4):null;
        
        TeamRanking teamRanking = new TeamRanking(Calendar.getInstance().getTime(), team1,
                team2, team3, team4, team5);
        
        teamRankingDao.save(teamRanking);
    }
    
    /*
    @Scheduled(cron="0 0 * * * ?")//midnight on every day
    public void removeOutdatedItems()
    { 
        Calendar calen = null;
        List<ItemRecord> lst = null;

        //
        
        calen = new GregorianCalendar();
        lst = this.itemRecordDao.findAll();
        for(ItemRecord rec : lst)
        {

            if(calen.after(rec.getExpirationDate()))
            { rec.getBag().removeEntry(rec); }   
        }
    }
    */
    
    protected long getNumberOfMaxLeaders(long numberUsers){
        return Math.max(MIN_NUMBER_OF_LEADERS, (long)(numberUsers * PERCENT_LEADERS));
    }
    
}
